import { onUnmounted } from "vue";

interface WorkerMessage<T = any> {
  id: number;
  data: T;
}

export function useWorker<T, R>(workerScript: string | Function) {
  let currentId = 0;
  const callbacks: Record<number, (data: R) => void> = {};

  const worker = typeof workerScript === "function" ? createInlineWorker(workerScript) : new Worker(workerScript);

  worker.onmessage = (e: MessageEvent<WorkerMessage<R>>) => {
    const { id, data } = e.data;
    if (callbacks[id]) {
      callbacks[id](data);
      callbacks[id] = undefined;
    }
  };

  function createInlineWorker(fn: Function): Worker {
    // const blob = new Blob([`(${fn.toString()})()`], { type: "application/javascript" });
    // return new Worker(URL.createObjectURL(blob));
    const blob = new Blob([`(${fn.toString()})()`], { type: "text/javascript" });
    return new Worker(URL.createObjectURL(blob));
  }

  function postMessage(data: T): Promise<R> {
    return new Promise(resolve => {
      const id = ++currentId;
      callbacks[id] = resolve;
      worker.postMessage(JSON.stringify({ id, data }));
    });
  }

  function terminate() {
    worker.terminate();
  }

  onUnmounted(() => {
    terminate();
  });

  return {
    postMessage,
    terminate
  };
}
